#ifndef _SLEP_H_
#define _SLEP_H_


#include "acml.h"
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <float.h>

#define maxof2(X,Y) (((Y)>(X))?(Y):(X))
#define DBLCOMPARE(X,NUM) ( (X<(NUM+0.0001)) && (X >(NUM-0.0001)) )

extern double* oneVector;
extern double Inf ;

typedef struct{
	double* x;
	double* funVal;
	double* ValueL;
	char type[20]; // strcpy the type here
	double c; // Used for logistic regression only
	int totIter; // Total Iterations that happened in this call
	int errorCode; // 0 for no error
}FUNVAL;

typedef struct{

	char registry[35];// Registry for set variables(used by internal function only). Don't modify by youself

	
	int m,n;  // dimensions

	//Starting points
	double* x0; // Starting x
	double c0; // Used in Logistic regression only
	double *mt_c0; // Used in mtLogistic regression only - c0 not used here
	double *mc_c0; // Used in mcLogistic regression only - c0 not used here


	int init; // Init takes values 0,1,2,3,4,5 default:2

	// Termination
	int maxIter;
	double tol;
	int tFlag;

	//Normalization
	int nFlag;
	double* mu;
	double* nu;

	//Method
	int method;
	int mFlag;
	int lFlag;

	//Regularization
	int rFlag;
	double rsL2;

	//Group and others
	int* ind;
	int ind_size;
	double q;
	double *gWeights;

	double sWeight[2]; // registry set to 'sWeight'
	int mc_k;
	// 2 more to come

}OPTS;

void initSLEP(int maxDimension);

void initOPTS(OPTS *opt,int m,int n,int k);
void setOPTx0(OPTS *opt,double* x0);
void setOPTc0(OPTS *opt,double c0);
void setOPTmtc0(OPTS *opt,double* mtc0);
void setOPTmu(OPTS *opt,double* mu);
void setOPTnu(OPTS *opt,double* nu);
void setOPTsWeight(OPTS *opt,double* sWeight);
void setOPTind(OPTS* opt,int* ind, int ind_size);
void setOPTq(OPTS* opt,double q);
void setOPTgWeights(OPTS* opt,double *gWeights);
int hasGot(OPTS *opt,char * field);

void initNormalization(OPTS *opt,double *A);
void normalizedmv(char trans,OPTS* opt,double* A, double* x, double* y);
void normalizedmv_lowlevel(char trans,int m,int n,double* A, int lda,double* x, double* y, int mstart, int nstart, OPTS *opt);


int terminationCondition(OPTS* opt, double fVal,double fValp, double* x, double norm_xxp,double norm_xp,int curIter);

void errorOut(char* errorMsg);

double dnrm(int n,double* x,int incx, double nrmbase);

FUNVAL LeastR(double* A, double* y, double z, OPTS opt);
FUNVAL LeastC(double* A, double* y, double z, OPTS opt);
FUNVAL glLeastR(double* A, double* y, double z, OPTS opt);
FUNVAL mcLeastR(double* A, double* y, double z, OPTS opt);
FUNVAL mtLeastR(double* A, double* y, double z, OPTS opt);
FUNVAL glLogisticR(double* A, double* y, double z, OPTS opt);
FUNVAL mcLeastC(double* A, double* y, double z, OPTS opt);
FUNVAL mtLogisticR(double* A, double* y, double z, OPTS opt);
FUNVAL mcLogisticR(double* A, double* y, double z, OPTS opt);

void normalizedMM(char trans, int m, int n, int k, double* A, double* x, double* y, OPTS* opt);


#endif